package com.smssalama;

import java.util.Vector;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.Ticker;

/**
 * <p>
 * Manages the display of alerts so that they are displayed serially, and they
 * dont override each other.
 * </p>
 * 
 * <p>
 * Alerts are stored in a queue and displayed in succession to avoid hiding each other.
 * When an Alert is dismissed, the next alert in the queue gets displayed.
 * </p>
 * 
 * <p>
 * {@link AlertManager#showDisplayable(Displayable)} and {@link AlertManager#showItem(Item)} 
 * can be used instead of {@link Display#setCurrent(Displayable)} and {@link Display#setCurrent(Item)} respectively.
 * In this case the {@link Displayable} or {@link Item} is displayed only after the last Alert in the queue.  
 * </p>
 * 
 * <p>
 * </p>
 * @author Arnold P. Minde
 * 
 */
public class AlertManager {

	/**
	 * A queue of the alerts to be displayed
	 */
	private static final Vector alertQueue = new Vector();
	
	/** 
	 * The {@link Displayable} or {@link Item} to be displayed after all the alerts in the {@link AlertManager#alertQueue} have been displayed
	 * 
	 */
	private static Object nextDisplayable = null;
	/**
	 * The {@link CommandListener} that is assigned to alerts, and handles alert's {@link Alert#DISMISS_COMMAND}.
	 * 
	 *  It invokes {@link AlertManager#handleAlertCommand()} which is synchronized
	 */
	private static final CommandListener commandListener = new CommandListener(){
		public synchronized void commandAction(Command command, Displayable displayable) {
			handleAlertCommand(displayable);
		}
	};
	
	/**
	 * Sets the {@link Displayable} or {@link Item} that should be displayed after the last {@link Alert} in the queue. 
	 * 
	 * @param object
	 */
	protected static synchronized void setNextDisplayable(Object object){
		if(object!=null){
			AlertManager.nextDisplayable = object;
		}
		if(AlertManager.nextDisplayable==null){
			AlertManager.nextDisplayable = Display.getDisplay(SMSSalama.getInstance()).getCurrent();
		}
	}
	/**
	 * Sets the {@link AlertManager#nextDisplayable} to nextDisplayable, and adds the alert in the queue.
	 * 
	 * @param alert
	 * @param nextDisplayable
	 */
	protected static synchronized void doShowAlert(Alert alert, Object nextDisplayable){
		setNextDisplayable(nextDisplayable);
		alert.setCommandListener(AlertManager.commandListener);
		if (AlertManager.nextDisplayable == null) {
			AlertManager.nextDisplayable = Display.getDisplay(
					SMSSalama.getInstance()).getCurrent();
		}
		AlertManager.alertQueue.addElement(alert);
		if (AlertManager.alertQueue.size() == 1) {
			AlertManager.showNext();
		}
	}
	
	/**
	 * If there are Alerts in the queue, displays the next alert in the queue. 
	 * Otherwise, it displays {@link AlertManager.nextDisplayable} if it is not empty. 
	 */
	protected static synchronized void showNext() {
		if (AlertManager.alertQueue.size() > 0) {
			Alert alert = (Alert) AlertManager.alertQueue.elementAt(0);
			//check that the alert at the top of the queue is not currently showing
			if(alert.isShown()){
				return;
			}
			Display.getDisplay(SMSSalama.getInstance()).setCurrent(alert);
		}else{
			if (AlertManager.nextDisplayable != null) {
				if (AlertManager.nextDisplayable instanceof Displayable) {
					Display.getDisplay(SMSSalama.getInstance()).setCurrent(
							(Displayable) AlertManager.nextDisplayable);
				} else if (AlertManager.nextDisplayable instanceof Item) {
					Display.getDisplay(SMSSalama.getInstance()).setCurrentItem(
							(Item) AlertManager.nextDisplayable);
				}
				AlertManager.nextDisplayable = null;
			}
		}
	}
	
	/**
	 * Invoked when {@link CommandListener}'s {@link CommandListener#commandAction(Command, Displayable)} of the {@link Alert}}'s command listener is called as the Alert is being dismissed.
	 * If the alerts queue is not empty, it calls {@link AlertManager#showNext()} to display next alert.
	 * Otherwise it displays {@link AlertManager.nextDisplayable} if it is not <code>null</code>. 
	 * @param displayable 
	 */
	private static synchronized void handleAlertCommand(Displayable displayable) {
		if (AlertManager.alertQueue.size() > 0 && AlertManager.alertQueue.elementAt(0) == displayable) {
			AlertManager.alertQueue.removeElementAt(0);
		}
		AlertManager.showNext();
	}

	public static synchronized void showAlert(Alert alert) {
		doShowAlert(alert, null);
	}

	public static synchronized void showAlert(Alert alert, Displayable nextDisplayable) {
		doShowAlert(alert, nextDisplayable);
	}

	public static synchronized void showAlert(Alert alert, Item nextItem) {
		doShowAlert(alert, nextItem);
	}

	public static synchronized void showError(Displayable displayable, Exception ex) {
		Alert a = new Alert("SMS Salama Error", ex.getMessage(), null, AlertType.ERROR);
		doShowAlert(a, displayable);
	}

	public static synchronized void showError(Item item, Exception ex) {
		Alert a = new Alert("SMS Salama Error", ex.getMessage(), null, AlertType.ERROR);
		a.setString(ex.getMessage());
		doShowAlert(a, item);
	}

	public static synchronized void showError(String errorMsg) {
		Alert alert = new Alert("SMS Salama Error", errorMsg, null,
				AlertType.ERROR);
		doShowAlert(alert, null);
	}

	public static synchronized void showDisplayable(Displayable displayable) {
		Ticker t= new Ticker(SMSSalamaSession.getSession().getLocale());
		displayable.setTicker(t);
		if(alertQueue.isEmpty()){
			Display.getDisplay(SMSSalama.getInstance()).setCurrent(displayable);	
		}else{
			nextDisplayable = displayable;
		}
	}

	public static synchronized void showItem(Item item) {
		if(alertQueue.isEmpty()){
			Display.getDisplay(SMSSalama.getInstance()).setCurrentItem(item);
		}else{
			nextDisplayable = item;
		}
	}
}
